#include "checks.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

extern "C" void L8_Fatal(const char* file, int line, const char* format, ...)
{
    char buf[256];

    va_list arguments;
    va_start(arguments, format);
    vsprintf(buf, format, arguments);
    va_end(arguments);

    fprintf(stderr, "FATAL: %s(%d): %s\n", file, line, buf);

    getchar();
    abort();
}

void CheckHelper(const char* file, int line, const char* source, bool condition)
{
    if (!condition)
    {
        L8_Fatal(file, line, "CHECK(%s) failed", source);
    }
}


void CheckEqualsHelper(const char* file, int line, const char* expected_source,
                       int expected, const char* value_source, int value)
{
    if (expected != value)
    {
        L8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n#   Expected: %i\n#   Found: %i",
                 expected_source, value_source, expected, value);
  }
}


void CheckNonEqualsHelper(const char* file, int line, const char* unexpected_source,
                          int unexpected, const char* value_source, int value)
{
    if (unexpected == value)
    {
        L8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %i",
                 unexpected_source, value_source, value);
    }
}

void CheckEqualsHelper(const char* file, int line, const char* expected_source,
                       const char* expected, const char* value_source, const char* value)
{
    if (strcmp(expected, value) != 0)
    {
        L8_Fatal(file, line,
                 "CHECK_EQ(%s, %s) failed\n#   Expected: %s\n#   Found: %s",
                 expected_source, value_source, expected, value);
    }
}

void CheckNonEqualsHelper(const char* file, int line, const char* expected_source,
                          const char* expected, const char* value_source, const char* value)
{
    if (expected == value || (expected != NULL && value != NULL && strcmp(expected, value) == 0))
    {
        L8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %s",
                 expected_source, value_source, value);
    }
}


void CheckEqualsHelper(const char* file,
                       int line,
                       const char* expected_source,
                       void* expected,
                       const char* value_source,
                       void* value)
{
    if (expected != value)
    {
        L8_Fatal(file, line,
                 "CHECK_EQ(%s, %s) failed\n#   Expected: %p\n#   Found: %p",
                 expected_source, value_source,
                 expected, value);
  }
}


void CheckNonEqualsHelper(const char* file,
                          int line,
                          const char* expected_source,
                          void* expected,
                          const char* value_source,
                          void* value)
{
    if (expected == value)
    {
        L8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %p",
                 expected_source, value_source, value);
    }
}


// Helper function used by the CHECK function when given floating
// point arguments.  Should not be called directly.
void CheckEqualsHelper(const char* file, int line, const char* expected_source,
                       double expected, const char* value_source, double value)
{
    // Force values to 64 bit memory to truncate 80 bit precision on IA32.
    volatile double* exp = new double[1];
    *exp = expected;
    volatile double* val = new double[1];
    *val = value;

    if (*exp != *val)
    {
        L8_Fatal(file, line,
                 "CHECK_EQ(%s, %s) failed\n#   Expected: %f\n#   Found: %f",
                 expected_source, value_source, *exp, *val);
    }

    delete[] exp;
    delete[] val;
}

